package com.google.jessewilson.codesearch.intellij;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import com.google.jessewilson.codesearch.api.Query;
import com.google.jessewilson.codesearch.ide.QueryHistory;
import com.google.jessewilson.codesearch.io.jdom.EasyElement;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

/**
 * A place where we can hang project-specific configuration data from,
 * such as recent search terms.
 *
 * @author jessewilson
 */
public class IntellijQueryHistory
    implements com.intellij.openapi.components.ProjectComponent,
    JDOMExternalizable, QueryHistory {

  private final Query.MyExternalizer queryExternalizer = new Query.MyExternalizer();
  private final EventList<Query> queryHistory = new BasicEventList<Query>();


  public IntellijQueryHistory() {
    // tmao(2007-09-11): Commenting this out pending discussion on how we're
    // going to handle externalizing state.

//    // create some initial history to provide sample data
//    queryHistory.add(new QueryBuilder()
//        .addQueryExtra(new GcsQueryExtra("\\.(java)$", "", false, true))
//        .addQueryExtra(new ClsSearchProviderParameters("-f=\\.(java)$", true))
//        .create());
//    queryHistory.add(new QueryBuilder()
//        .addQueryExtra(new GcsQueryExtra("\\.(java)|(xml)$", "(uwaterloo\\.ca)|(mit\\.edu)", false,
//            true))
//        .addQueryExtra(new ClsQueryExtra("-f=\\.(java)|(xml)$", true))
//        .create());
//    queryHistory.add(new QueryBuilder()
//        .addQueryExtra(new GcsQueryExtra("\\.(java)|(xml)|(txt)$", "sourceforge\\.net", false,
//            true))
//        .addQueryExtra(new ClsQueryExtra("-f=\\.(java)|(xml)|(txt)$", true))
//        .create());
  }

  public EventList<Query> getElements() {
    return queryHistory;
  }

  public List<Query> getSnapshot() {
    getElements().getReadWriteLock().readLock().lock();
    try {
      return new ArrayList<Query>(getElements());
    } finally {
      getElements().getReadWriteLock().readLock().unlock();
    }
  }

  public void postQuery(Query query) {
    // save the query term in history
    queryHistory.getReadWriteLock().writeLock().lock();
    try {
      queryHistory.remove(query);
      queryHistory.add(0, query);
    } finally {
      queryHistory.getReadWriteLock().writeLock().unlock();
    }
  }

  @NonNls
  @NotNull
  public String getComponentName() {
    return "CodeSearch/QueryHistory";
  }

  public void initComponent() {
    // load history from file?
  }

  public void disposeComponent() {
    // store history to file?
  }

  public void projectOpened() {
  }

  public void projectClosed() {
  }

  public void readExternal(Element element) throws InvalidDataException {
    queryHistory.getReadWriteLock().readLock().lock();
    try {
      queryHistory.clear();
      for(EasyElement queryElement : new EasyElement(element).getChildren()) {
        Query query = queryExternalizer.readExternal(queryElement.getElement());
        queryHistory.add(query);
      }
    } finally {
      queryHistory.getReadWriteLock().readLock().unlock();
    }
  }

  public void writeExternal(Element element) throws WriteExternalException {
    queryHistory.getReadWriteLock().readLock().lock();
    try {
      EasyElement queriesElement = new EasyElement(element);
      for(Query query : queryHistory) {
        EasyElement queryElement = new EasyElement("query");
        queryExternalizer.writeExternal(queryElement.getElement(), query);
        queriesElement.addChild(queryElement);
      }
    } finally {
      queryHistory.getReadWriteLock().readLock().unlock();
    }
  }
}
